import got, { type Request } from "got";
import { type BrowserWindow } from "electron";
import { createWriteStream } from "fs";
import path from "node:path";
import fs from "node:fs";
import { EventEmitter } from "events";
import type { DownloadCompleteArgs, DownloadErrorArgs } from "@common/http-service-types";

export interface _DownloadProgressArgs {
  transferred: number;
  total: number;
  percent: number;
}

export class DownloadTask extends EventEmitter {
  private _ds?: Request;

  constructor(
    readonly id: string,
    readonly url: string,
    readonly savePath: string,
    readonly wind: BrowserWindow | undefined,
  ) {
    super();
  }

  private get webContents() {
    return this.wind?.webContents;
  }

  start() {
    const saveDir = path.dirname(this.savePath);
    if (!fs.existsSync(saveDir)) {
      fs.mkdirSync(saveDir, { recursive: true });
    }
    const outStream = createWriteStream(this.savePath);
    const stream = got.stream(this.url);
    stream.on("downloadProgress", this._onProgress);
    stream.on("error", this._onError);
    stream.on("end", this._onEnd);
    stream.pipe(outStream);
  }

  private _onProgress = (args: _DownloadProgressArgs) => {
    if (args.total > 0) {
      this.webContents?.send(`file:download:progress:${this.id}`, args);
    }
  };

  private _onError = (err: Error) => {
    this.webContents?.send(`file:download:error:${this.id}`, <DownloadErrorArgs>{
      message: err.message,
    });
    this.emit("error", err);
    this._deleteSaveFile();
  };

  private _onEnd = () => {
    this.webContents?.send(`file:download:complete:${this.id}`, { filePath: this.savePath } as DownloadCompleteArgs);
    this.emit("complete");
  };

  private _deleteSaveFile() {
    if (fs.existsSync(this.savePath)) {
      fs.rmSync(this.savePath, { force: true, maxRetries: 3, retryDelay: 300 });
    }
  }

  cancel() {
    this._ds?.destroy();
    this._deleteSaveFile();
  }

  pause() {
    this._ds?.pause();
  }

  resume() {
    this._ds?.resume();
  }
}
